using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;

namespace WebSpider
{
    public partial class Form1 : Form
    {
        private readonly List<string> _urls = new List<string>();

        public Form1()
        {
            InitializeComponent();
        }

        private async void btnSearch_Click(object sender, EventArgs e)
        {
            string keyword = txtKeyword.Text.Trim();
            if (string.IsNullOrEmpty(keyword))
            {
                MessageBox.Show("Please enter a keyword to search.");
                return;
            }

            await SearchAsync(keyword);
        }

        private async Task SearchAsync(string keyword)
        {
            // Define search engine URLs
            string[] searchUrls = new[]
            {
                $"https://www.baidu.com/s?tn=68018901_17_oem_dg&ie=utf-8&wd={WebUtility.UrlEncode(keyword)}",
                $"https://www.bing.com/search?q={WebUtility.UrlEncode(keyword)}&mkt=zh-CN"
            };

            // Define regular expression for phone numbers
            string phoneRegex = @"\d{11}";

            // Define tasks for each search engine
            var tasks = new List<Task<IEnumerable<string>>>();
            foreach (string url in searchUrls)
            {
                tasks.Add(SearchEngineAsync(url, phoneRegex));
            }

            // Update progress bar
            progressBar1.Value = 0;
            progressBar1.Maximum = tasks.Count;

            // Wait for all search engine tasks to complete
            var results = await Task.WhenAll(tasks);

            // Merge search results and remove duplicates
            var phones = results.SelectMany(r => r).Distinct().ToList();

            // Limit the number of phones to 100
            phones = phones.Take(100).ToList();

            // Display phones and their URLs
            listBox1.Items.Clear();
            foreach (string phone in phones)
            {
                string urls = string.Join(", ", _urls.Where(u => u.Contains(phone)));
                listBox1.Items.Add($"{phone}: {urls}");
            }

            // Reset progress bar
            progressBar1.Value = 0;
            progressBar1.Maximum = 100;
        }

        private async Task<IEnumerable<string>> SearchEngineAsync(string url, string phoneRegex)
        {
            // Download search results page
            string html = await DownloadAsync(url);

            if (html == null)
            {
                Console.WriteLine("Error HTML is null");
                return new List<string>();
            }

            // Find URLs in search results page
            var urls = FindUrls(html);

            // Download each URL and find phone numbers
            var phones = new List<string>();
            int progress = 0;
            progressBar1.Value = 0;
            progressBar1.Maximum = urls.Count();
            foreach (string u in urls)
            {
                string pageHtml = await DownloadAsync(u);
                phones.AddRange(FindPhones(pageHtml, phoneRegex));
                progress++;
                int currentValue = (int)Math.Round(progress * 100.0 / urls.Count());
                progressBar1.Value = Math.Min(progressBar1.Maximum, currentValue);
            }

            // Add URLs to global URL list for display
            _urls.AddRange(urls);

            return phones;
        }

        private async Task<string> DownloadAsync(string url)
        {
            if (url.StartsWith("javascript:", StringComparison.OrdinalIgnoreCase))
            {
                Console.WriteLine($"Error downloading {url}: The 'javascript' scheme is not supported.");
                return null;
            }

            try
            {
                using var client = new HttpClient();
                return await client.GetStringAsync(url);
            }
            catch (HttpRequestException ex)
            {
                Console.WriteLine($"Error downloading {url}: {ex.Message}");
                return null;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error downloading {url}: {ex.GetType().FullName}: {ex.Message}");
                return null;
            }
        }

        private IEnumerable<string> FindUrls(string html)
        {
            // Define regular expression for URLs
            string urlRegex = @"(?<=href="")[^""]*(?="")";

            // Find all URLs in HTML using regular expression
            MatchCollection matches = Regex.Matches(html, urlRegex);

            // Convert matched URLs to absolute URLs
            var urls = new List<string>();
            foreach (Match match in matches)
            {
                string u = match.Value;
                if (Uri.TryCreate(u, UriKind.Absolute, out Uri absoluteUri))
                {
                    urls.Add(absoluteUri.ToString());
                }
            }

            return urls;
        }

        private IEnumerable<string> FindPhones(string html, string phoneRegex)
        {
            if (html == null)
            {
                Console.WriteLine("Error HTML is null");
                return new List<string>();
            }
            // Find all phone numbers in HTML using regular expression
            MatchCollection matches = Regex.Matches(html, phoneRegex);

            // Convert phone number matches to list of strings
            return matches.Select(m => m.Value).ToList();
        }
    }
}